於前篇提了方法的 Input
現在來講 OutPut
Output 可就不像是Input 那麼單純了
就從最基本的開始吧
object Method(object input)
一來一往一進一出,是正拳
這就不評論優缺點了,正拳就是努力練就會越變越好,而且每天都在用
IEnumerable<Object> Method(object input)
回傳序列是很重要的 不是集合喔
一班來說在c#一組物件要在方法中穿梭都盡量會使用IEnumerable<>而不是Array or List
基於它的作用方式可避免消耗過大與運作加速 (註2)
在C#上近乎無敵的做法,只是他碰上Task的時候還是會可能會讓很多人苦手(註3)
名稱太長要寫很久,而且很難記
Action<T> Method(object input)
呼叫傳送門的概念
帶入素材,執行方法,獲得一個任(泛)意(型)門(Entry)
其實這樣用的情境還滿少的
通常這表示一個設定過程或是委派本身會成為主要傳遞型別
但其實最不願意這樣寫的理由還是因為這等於是要使用者寫Method(obj)(other)
挖坑給別人跳的概念!?
Func<T> Method(object input)
建造工廠? Build a Factory
回傳Func<>其實算是常用的寫法
例如像是 Builder<> Build Factory<> 然後 Factory<> Create 目標
Factory就是Func<>所以這是一種Pattern
ResultObject Method(object input,out object output)
我自己倒是真的不喜歡這樣寫
這種狀況多半都類似需要回傳兩種不同型別的物件時使用
例如 bool TryParse(object obj,out T val)
但是這樣一寫兩邊都造成了困擾
所以後來在 C# 7的時候前後都有了改善
Input方可以寫Pattern Matching
Method(input,out var output) ? output : other
而Output方也可以以最簡單的方式改成 ValueTuple的作法
(bool,T) Method(object input)
但我會更喜歡接下來這個做法
void Method(T object, Action<object> callback)
有一種濃濃的 Reactive 味道
這種做法的概念就是,有事再叫我
這樣寫的好處很多,而且有非常多經典的模式都是長這樣
例如 Castle Dynamic Proxy,Interceptor Pattern,Owin Middleware
不過高自由的就代表著並不好懂
簡單舉例其中一種用法,利用這種作法搭配 Task,在 Owin 中比較常見的 Middleware
async Task Invoke(HttpContext context,Func<HttpContext,Task> next)
{
//before next....
awawit next(context);
//after next.....
}
IDisposable Method<T>(Action<T> next,Action<Exception> error,Action complete)
就是這個味
上面都提了,那當然不能錯過這個狠腳色,他回傳的可不只是一個參數
他回傳的是一組完整的try/cache/finally + disposer
想像一下這結構大概像是這樣,順便幫這位高手正名一下
public class Observable : IObservable,IDisposable
{
private IObserver _observer;
public Observable(IObserver observer)
{
this._observer = observer;
}
public void Run(object obj)
{
try
{
_observer.Next(obj);
}
cache(Exception ex)
{
_observer.Error(ex);
}
finally
{
_observer.Complete();
}
}
public IDisposable Subscribe<T>(IObserver observer)
=> new Observable(observer);
public void Dispose()
{
(_observer is IDisposable disposer
? disposer.Dispose
: Empty.Action)();
_observer = default;
}
}
這就是前面所說的,他不只給你一個回傳值
他給你的是一整個架構完整的結構
void Method<T>(T target) where T : class
這不是跑錯鵬唷
這其實只是借用了 class 的 Reference特性在方法運作完之後繼續往後使用而不是等待回傳
這樣做可以確保物件不會被換過 ex: IConfigureOptions<>
所以相較之下第一種方法就會是可以被置換的作法 ex: ModelBuilder
看了那麼多種回應的方式,前一篇那種Input真的接得起來嗎?
就讓我們繼續看下去吧
Task.Run
實際開始運作的時間點會被再延後,而同樣的Func<Task>
也是同等案例 附上官網警示